﻿/*==========================================================【程式資訊及版權宣告】====
  SSCkeyboard
  Copyright(Pe) 2000-2011.
  fixed : 1.08
	1.08(15/03/2011)
	* JQuery Support
	* Numpan 0~9 -> Numpad0~9 // my fault..
	* ssc_keyboard_init(); // auto create a panel at document.all.body
	* Auto add Keydown/up event when JQuery ready.
	1.07(26/09/2010)
	* renewhotkey() upgraded
	1.06(31/10/2007)
	* FF use event.which to get keyCode fix keydown/keyup
	* add browser check ....
	* some key what different keyCode between IE,FF,NS..etc
	** add keyfix when keydown / keyup
	1.05(28/9/2007)
	* fix FireFox can't detect event.keyCode | event.which
	* fix disableallkey would not be able when Firefox, also Firefox didn't return function keyCode
	1.04 (1/3/2006)
	* ssc_clsbind() used to init/renew the current keybind
	* renewhotkey(tmparr)
	** easy to set the mutilevel hotkey
	* Debug rewrite
	1.03 (14/6/2005)
	* in ssc_lib auto config
	* keystat split to "keystat" & "key_func_stat"
	* support Twin key active function
	** keybind format change keybind(acsii,twinkey,action,muit)
	** dose not support client version before 1.02
	1.02 (22/05/2004)
	* blindkey function can be string or function(){'..'}
	  Auto select in program
	* ssc_keyboard stats auto create with ssc_keyboard_init(tag_id)
	  detial will be write in the "tag_id" which selected by user.
	1.01 (14/09/2003)
	* fixed blindkeyup setting "after" error
======================================================================================
程式用法
 ssc_keyboard_init(obj)
	obj = body 物件，於其物件下生成本系統專用 debug 清單，顯示按鍵
 ssc_clsbind()
	清除現有所有鍵之功能，還原用
 renewhotkey(arr)
	依照導入 arr 重定熱鍵動作。已包含 ssc_clsbind 功能
	Usage:
	var arr1 = [
		{
			key1 : "esc",
			key2 : "",
			action: function(){ display("",true) }, // by function
			repeat: true
		},
		{
			key1 : "Space Bar",
			key2 : "",
			action: " alert('Space Bar') ", // by String
			repeat: false
		}
	];
	renewhotkey(arr1)

-- 預定設定：(使用 ssc_lib 不用設定) --
   <script src="keyboard.js"></script>
   <script>
   var keyfps = 50;		// 預設的重複執行微秒
   function document.onkeydown(){ ssc_keydown(window.event); }
   function document.onkeyup(){ ssc_keyup(window.event); }
   </script>

-- 設定方式(簡單之個別設定) --
keybind(acsii,twinkey,action,muit)
keybindup(acsii2,action2)

-- 設定方式(功能表單用) --
//step1A)
	var arr = [
	["鍵",	"鍵",		執行功能,	按著不放則重覆執行],
	["Ctrl","Space Bar",	new Function(),	false]
	]
// step2A)
// 初始化現有鍵與功能
renewhotkey(arr);

使用功能表方式設定不同之 hotkeyarr, 可隨時使用 renewhotkey 更換製作多重選單熱鍵
======================================================================================
  程式原作者: 天機–絕版危機(Canis TK)
    個人網站: http://www.clonefactor.com
    電子郵件: canistk@gmail.com
　MSN 帳號: canistk@yahoo.com
    ICQ 帳號: 22224880
    發表日期: 2003.09.14
======================================================================================

    版權所有
    請尊重智慧財產權： 無論您對本程式 SSCkeyboard 作任何修改請您*必須*保留此段版權宣告
    的內容，原作者的名字和網站連結。

    如果您想要以這個程式為基礎，製作以及公開發表您所修改過的版本，
    請您首先以傳送電子郵件的方式，徵求我們的同意。

    請不要將原作者的名字改成您自己的名字，然後以另一程式名稱重新命名後在網路上公開發表
    及散播本程式，因為這是嚴重的侵權行為。

    這是公益免費程式，所以請不要使用在商業用途上。
    另外，您亦不可將本程式(全部或部份)複製到其他儲存媒體(例如光碟片)上作販賣獲利用~。

    假如因為使用本程式而令您蒙受資料遺失或損毀，程式原作者均不用對其負責。

===以下為程式內碼===================================================================*/
var keyfps = 50;		// 預設的重複執行微秒
var clock;			// 用於 setInterval 的變量
ssc_commandrate = new Array();	// 各鍵功能重複處理 Array Loop
ssc_keyrec = new Array();	// 記錄目前按下鍵，整修用
ssc_key = new Array(223);	// 222 個鍵的初始化

var ssc_keyboard=false;		// 用於回報狀況 default[ 不回報 ]

//------------------------------------------------鍵名稱初始

// 建立/消除 ssc_key 內之設定值
function ssc_clsbind(){
for(var i=0; i<223; i++) ssc_key[i] = new key_class();
ssc_key[8].name = "BackSpace";
ssc_key[9].name = "Tab";
ssc_key[12].name = "Center";
ssc_key[13].name = "Enter";
ssc_key[16].name = "Shift";	//***Function key
ssc_key[17].name = "Ctrl";	//***Function key
ssc_key[18].name = "Alt";	//***Function key
ssc_key[19].name = "Pause";
ssc_key[20].name = "Caps Lock";
ssc_key[27].name = "Esc";
ssc_key[32].name = "Space Bar";
ssc_key[33].name = "Page Up";
ssc_key[34].name = "Page Down";
ssc_key[35].name = "End";
ssc_key[36].name = "Home";
ssc_key[37].name = "Arrow Left";
ssc_key[38].name = "Arrow Up";
ssc_key[39].name = "Arrow Right";
ssc_key[40].name = "Arrow Down";
ssc_key[44].name = "Print Screen"; //***Function key
ssc_key[45].name = "Insert";
ssc_key[46].name = "Delete";
for (i=48; i<=57; i++)
	ssc_key[i].name = String.fromCharCode(i);
for (i=65; i<=90; i++)
	ssc_key[i].name = String.fromCharCode(i);
ssc_key[91].name = "Start Menu(L)"; //***Function key
ssc_key[92].name = "Start Menu(R)"; //***Function key
ssc_key[93].name = "Menu"; //***Function key
ssc_key[96].name = "Numpad 0";
ssc_key[97].name = "Numpad 1";
ssc_key[98].name = "Numpad 2";
ssc_key[99].name = "Numpad 3";
ssc_key[100].name = "Numpad 4";
ssc_key[101].name = "Numpad 5";
ssc_key[102].name = "Numpad 6";
ssc_key[103].name = "Numpad 7";
ssc_key[104].name = "Numpad 8";
ssc_key[105].name = "Numpad 9";
ssc_key[106].name = "Numpad *";
ssc_key[107].name = "Numpad +";
ssc_key[109].name = "Numpad -";
ssc_key[110].name = "Numpad .";
ssc_key[111].name = "Numpad /";
for (i=112; i<=123; i++)
	ssc_key[i].name = "F"+(i-111);
ssc_key[144].name = "Num Lock";
ssc_key[145].name = "Scroll Lock";
ssc_key[186].name = ";";	// ; 
ssc_key[187].name = "=";	// =
ssc_key[188].name = ",";	// ,
ssc_key[189].name = "-";	// -
ssc_key[190].name = ".";	// .
ssc_key[191].name = "/";	// /
ssc_key[192].name = "`";	// `
ssc_key[219].name = "[";	// [
ssc_key[220].name = "\\";	// \ 
ssc_key[221].name = "]";	// ]
ssc_key[222].name = "'";	// '
} // End ssc_clsbind()
ssc_clsbind();
//----------------------------------------------------------設定完畢

//------------------------------------------------麻煩的瀏覽器
browser = 
    (navigator.appName.indexOf('Microsoft') != -1) ? 1 :
    (navigator.appName.indexOf('Netscape')  != -1) ? 2 :
    (navigator.appName.indexOf('Opera')     != -1) ? 3 :
    4;
if(browser == 2 && navigator.userAgent.indexOf('Safari') != -1) browser = 5;


//------------------------------------------------鍵的功能初始
function key_class() {
 this.name	=	"NONE";	// 鍵名
 this.action	=	new Array();	// 寫入的執行指令 keydown
 this.twinkey	=	new Array();	// 組合鍵
 this.muit	=	new Array();	// 啟動重複執行
 this.actionup	=	new Array();	// 寫入的執行指令 keyup
 this.key_func_stat	=false;	// 運行式狀態
 this.keystat	=	false;	// 鍵狀態
 return this;
}
//------------------------------------------------錯誤修正 各種不明錯誤....
function keyfix(e){
	/*
	 59 ";" 分號和冒號, IE = 186
	61 "=" firfox keycode, 187: "=" //ie keycode
	189 "-" in firfox keycode = 109 as same as "numpad =" can't fix....
	
	*/
	if(browser!=1) switch(e){
		case 59: e=186; break; // ";"
		case 57383: case 109: e=189;break; // The "numpad -" also turn to "-" key.... mush select one.
		case 57384: case 61: e=187; break; // "-"
		case 57402: e=17; break; //Ctrl Opera 7.11
		case 57356: e=123; break; // F12 Opera 7.11
	}//end switch when not in IE
	return e;
}//End keyfix


//------------------------------------------------重複處理核心
function ssc_repeataction(){
 var ck=null;
 if(ssc_keyboard) ssc_keyboard_repeat.value="";
 if(ssc_commandrate.length!=0)
	for(i=0; i<ssc_commandrate.length; i++){
		if(ssc_key[ssc_commandrate[i][0]].keystat==true && ssc_key[ssc_commandrate[i][0]].muit[(ssc_commandrate[i][1])] != false){ // 重複及按鍵撿查
			ck = ssc_key[ssc_commandrate[i][0]].action[(ssc_commandrate[i][1])];
			if(ssc_keyboard) ssc_keyboard_repeat.value+= "["+ssc_key[ssc_commandrate[i][0]].name+"]="+ck+"\n==================\n";
			switch(typeof ck){
				case 'string':new Function( eval(ck) );break;
				case 'function':ck();break;
			} // End-switch
		}else{
			ssc_commandrate.splice(i--,1);	// 刪除
		} // End-if
	}// End-for
 if(ssc_keyboard) ssc_keyboard_update();
} // End-scc_repeataction

function ssc_keydown(in_e) {
 var e = in_e;
 if(!in_e) in_e=window.event;
 var ekey = in_e.which ? in_e.which : in_e.keyCode;
 ekey = keyfix(ekey);
 var ck=null;	// tmp use key action
 var tk=null;	// tmp use Twin key
 var passtk=true;	// check if function have double key press to active
 if(ekey >=8 && ekey <=222){
	ssc_key[ekey].keystat = true;		// 按鍵狀態
	if (ssc_key[ekey].key_func_stat == false){	// 執行處理
	for(i=0; i<ssc_key[ekey].action.length; i++){
		if (ssc_key[ekey].twinkey[i]!="NONE"){		// 組合鍵處理
			passtk = false;					// 存在 Twinkey 預設值
			tk = ssc_key[ekey].twinkey[i];
			passtk = ssc_key[key_check(tk)].keystat; 	// Twin 狀態確認
		} // End-if
		if(ssc_key[ekey].action[i] != "NONE" && passtk){
			ck = ssc_key[ekey].action[i];
			switch(typeof ck){
				case 'string':new Function( eval(ck) ); break;
				case 'function':ck(); break;
			} // End-switch
		} // End-if
		if(ssc_key[ekey].muit[i] == true){
			// 寫入重複處理排程
			ssc_commandrate[ssc_commandrate.length] = [ekey,i]; 
		} // End-if
		ssc_key[ekey].key_func_stat = true;	// 運行式狀態
	} // End-loop
		if(ssc_keyboard==true) {		// Debug log 記錄
			this.check=true;
			for(i=0; i<ssc_keyrec.length; i++)
			 if(ssc_keyrec[i]==ssc_key[ekey].name) { this.check=false; }
			if(this.check==true) ssc_keyrec[ssc_keyrec.length] = ssc_key[ekey].name;
		} // End-if ssc_keyboard
	} // End-if ekey
	disableAllKeys(e);
 } // End-if
} // End-ssc_keydown

function ssc_keyup(in_e) {
 var e = in_e;
 if(!in_e) in_e=window.event;
 var ekey = in_e.which ? in_e.which : in_e.keyCode;
 ekey = keyfix(ekey);
 var ck=null;
 if(ekey >=8 && ekey <=222) {
	ssc_key[ekey].keystat = false;
	if (ssc_key[ekey].key_func_stat == true){	// 運行式處理中
		for(i=0; i<ssc_key[ekey].actionup.length; i++){
			if(ssc_key[ekey].actionup[i] != "NONE"){
				ck = ssc_key[ekey].actionup[i];
				switch(typeof ck){
					case 'string':eval(ck);break;
					case 'function':ck();break;
				} // End-switch
			} // End-if
		} // End-loop
	} // End-if
	if(ssc_keyboard==true) {			// Debug log 記錄
		for(i=0; i<ssc_keyrec.length; i++)
		 if(ssc_keyrec[i]==ssc_key[ekey].name) { ssc_keyrec.splice(i--,1); break; }// 把清單重排
	} // End-if
	ssc_key[ekey].key_func_stat = false;	// 運行式重置
	disableAllKeys(e);
 } // End-if
} // End-ssc_keyup

function key_check(acsii){	// 把 222 內 Acsii code 轉換為 ssc_key[].name 的初始值
	if (acsii >= 0 && acsii <= 222 && typeof(acsii) !="string") {
		return acsii;
	} else {
	 for (var i=0; i<=222; i++) {
		if (ssc_key[i].name.toLowerCase() == acsii.toLowerCase()){
			return i;
			break;
		} // End-if
	 } // End-loop
	} // End-if
} // End-key_check

function keybind(acsii,twinkey,action,muit){
	acsii = key_check(acsii);
	twink = "NONE";
	key_r = (ssc_key[acsii].action).length;
	switch (arguments.length){
		case 4: // muit
		case 3: // action
		case 2: // twinkey
			if (twinkey!=null && twinkey!='' && twinkey != false && (typeof twinkey !='undefined'))
			twink = key_check(twinkey);
		case 1: // acsii
		default:
			ssc_key[acsii].muit[key_r] = (typeof muit !='undefined')? muit : false;
			ssc_key[acsii].twinkey[key_r] = twink;
			ssc_key[acsii].action[key_r] = action;	// 把 case 3 設好的 action 輸入
		break;
	} // End-switch
} // End-keybind

function keybindup(acsii2,action2){
	acsii2 = key_check(acsii2);
	key_r = (ssc_key[acsii2].actionup).length;
	ssc_key[acsii2].actionup[key_r] = action2;
} // End-keybindup

// For setting the hotkey use
function renewhotkey(tmparr){
	ssc_clsbind();	// clear current setting.
	for(tmp=0; tmp<tmparr.length; tmp++){
		// keybind(tmparr[tmp][0],tmparr[tmp][1],tmparr[tmp][2],tmparr[tmp][3]);
		keybind(tmparr[tmp].key1,tmparr[tmp].key2,tmparr[tmp].action,tmparr[tmp].repeat);
	}//for
}// renewhotkey();



function ssc_keyboard_init(){	// 整修用鍵狀態表單生成
	// obj must be Jquery object.
	$("body").append("<span id='ssc_keyboard' style='position:fixed;>position:absolute;top:0;left:0;z-index:9999;background:#FFF;'>"+
			"keypressing :<br/>"+
			"<textarea id='ssc_keyboard_history' cols='35' rows='10'></textarea><br/>"+
			"Repeat status \\ keyfps : <br/>"+
			"<span id='ssc_keyboard_keyfps'></span><br/>"+
			"<textarea id='ssc_keyboard_repeat' cols='35' rows='10'></textarea>");
	ssc_keyboard=true;
} // End-ssc_keyboard_init

// 把 keyboard 的資訊列印於 ssc_keyboard_rate.innerHTML 內
function ssc_keyboard_update(){
	ssc_keyboard_keyfps.innerText = keyfps;
	this.temp="";
	if(ssc_keyrec.length!=0)
		for(i=0; i<ssc_keyrec.length; i++)
			this.temp += "["+ ssc_keyrec[i] +", "+key_check(ssc_keyrec[i])+"]="+ ssc_key[(key_check(ssc_keyrec[i]))].action.toString() +"\n==================\n";

	ssc_keyboard_history.value ='';
	ssc_keyboard_history.value = this.temp;
} // End-ssc_keyboard_update

// 原有功能鍵禁止
// 不能禁止 Print screen, Ctrl+Alt+del 系統層面熱鍵
// 進入 text / textarea 時本功能關閉
function disableAllKeys(e){
	try{
	if(e.srcElement.type != "text" && e.srcElement.type!="textarea" && e.srcElement.type != "password"&& e.srcElement.type != "button"&& e.srcElement.type != "checkbox")	{
		if(window.event){
			//window.event.keyCode = 0;
			window.event.returnValue = false;
		}else{		
			//event.which = 0;
			event.returnValue = false;
		}//end-if event		
	} // End-if
	}catch(ee){}
} // End-disableAllkeys

// 使用 addEventHandler 需 ssc_lib support
if (typeof(addEventHandler) != "undefined"){
	addEventHandler(document,'keydown',ssc_keydown);
	addEventHandler(document,'keyup',ssc_keyup);
}
// 使用 Jquery add handler
try{
	$(document).ready(function(){
		$(document).keydown(function(event){ ssc_keydown(event); });
		$(document).keyup(function(event){ ssc_keyup(event); });
	});
}catch(e){}
clock = setInterval("ssc_repeataction()",keyfps); // Timer 處理